import json
import time
from concurrent.futures import ThreadPoolExecutor

from paho.mqtt import client as mqtt_client
from paho.mqtt.client import MQTT_LOG_INFO, MQTT_LOG_WARNING

import baseScript

fail_user = {}
cont_fail_user = {}
n = 0
unexpected_disconnection = 0
connect_success = 0
count_push_num = 0
logger = baseScript.logger
send_success = 0
received_success = 0

def connect_mqtt(broker, port, appGuestName, appGuestPassword, appGuestReceiveTopic, client_id, username):
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            global connect_success
            connect_success += 1
            logger.info(f"Connected to MQTT Broker!")
            logger.info(f"connect_success = {connect_success}")
        else:
            if rc == 1:
                logger.warning('Connection refused - incorrect protocol version')
            if rc == 2:
                logger.warning('incorrect protocol version')
            if rc == 3:
                logger.warning('Connection refused - server unavailable')
            if rc == 4:
                logger.warning('Connection refused - bad username or password')
            if rc == 5:
                logger.warning('Connection refused - not authorised')
            if rc >= 6 and rc <= 255:
                logger.warning('Currently unused ')
            logger.info("Failed to connect, return code %d\n", rc)

    def _on_connect_fail(client, userdata):
        logger.error(f'{username}连接失败')
        cont_fail_user.update({username: 'cont_fail'})

    def _on_disconnect(client, userdata, rc):
        if rc != 0:
            global unexpected_disconnection
            unexpected_disconnection += 1
            logger.error(f"Unexpected disconnection = {unexpected_disconnection}")

    client = mqtt_client.Client(client_id)
    client.username_pw_set(appGuestName, appGuestPassword)
    client.on_connect = on_connect
    client.connect(broker, port)
    client.on_log = _log_callback
    client.on_connect_fail = _on_connect_fail
    client.on_disconnect = _on_disconnect
    return client


def _log_callback(client, userdata, level, buf):
    # logger.info(buf)
    pass

def publish(client, appGuestSendTopic, cookie):
    i = 1
    while 1:
        time.sleep(15)
        msg = {
            "token": cookie,
            "messageType": "APP_SEND_SELF_ADJUSTMENT_PARAM",
            "msgBody": {
                "earType": "RIGHT",
                "xAxis": 0 if i % 2 == 0 else 1,
                "yAxis": 1,
                "programNumber": 0
            },
            "sendTime": "2023-03-07 08:06:10"
        }
        # logger.info(client.is_connected())
        msg = json.dumps(msg)
        result = client.publish(appGuestSendTopic, msg)
        # result: [0, 1]
        status = result[0]
        if status == 0:
            # logger.info(f"Send '{msg}' to topic '{appGuestSendTopic}'")
            global send_success
            send_success += 1
            logger.info(f"send_success = {send_success}")
            # pass
        else:
            logger.info(f"Failed to send message to topic '{appGuestSendTopic}'")
        i += 1


def subscribe(client, appGuestReceiveTopic):
    def on_message(client, userdata, msg):
        # logger.info(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
        global received_success
        received_success += 1
        logger.info(f"Received_success = {received_success}")
    client.subscribe(appGuestReceiveTopic)
    # logger.info(appGuestReceiveTopic)
    client.on_message = on_message


def run(username):
    # 登录 - 获取mqtt 接口 -
    """admin用户登录"""
    # appGuestReceiveTopic = 'get_conf["appGuestReceiveTopic"]'+username
    # broker = '47.102.214.108'
    # port = 1883
    # appGuestName = 'admin'
    # appGuestPassword = 'artemisAdmin123@cloud.com'
    # # appGuestPassword = 'admin'
    # appGuestReceiveTopic = f'platformRetoneFit/manager/receive/'+username
    # client_id = 'python/' + username
    # client = connect_mqtt(broker, port, appGuestName, appGuestPassword, appGuestReceiveTopic, client_id, username)
    # 登录
    cookie = baseScript.login(username, 'cc1234')
    # 使用cookie 获取mqtt 配置信息
    # cookie = username
    get_conf = baseScript.mqtt_conf(cookie)
    # logger.info('Cookie = ', cookie, 'get_conf = ', get_conf)
    broker = get_conf['url']
    # port = get_conf['port']
    port = 1883
    appGuestPassword = '123456@appGuest.retone'
    appGuestName = 'appGuest'
    appGuestSendTopic = get_conf['appGuestSendTopic']
    client_id = get_conf['appGuestReceiveClientId']
    appGuestReceiveTopic = get_conf['appGuestReceiveTopic']
    client = connect_mqtt(broker, port, appGuestName, appGuestPassword, appGuestReceiveTopic, client_id, username)
    # client.loop_start()
    # 连接订阅消息
    subscribe(client, appGuestReceiveTopic)
    # publish(client, appGuestSendTopic, cookie)
    # time.sleep(2)
    client.loop_forever()
    # client.loop_stop()
    # client.disconnect()


def run_publish(username):
    cookie = baseScript.login(username, 'cc1234')
    # cookie = username
    get_conf = baseScript.mqtt_conf(cookie)
    # logger.info(f'Cookie =, {cookie}, get_conf = {get_conf}')
    broker = get_conf['url']
    # port = get_conf['port']
    port = 1883
    appGuestPassword = get_conf['appGuestPassword']
    appGuestName = get_conf['appGuestName']
    appGuestSendTopic = get_conf['appGuestSendTopic']
    client_id = get_conf['appGuestReceiveClientId']
    appGuestReceiveTopic = get_conf['appGuestReceiveTopic']
    client = connect_mqtt(broker, port, appGuestName, appGuestPassword, appGuestReceiveTopic, client_id, username)
    client.loop_start()
    subscribe(client, appGuestReceiveTopic)
    publish(client, appGuestSendTopic, cookie)
    # client.loop_forever()
    client.loop_stop()


def __run(cookie):
    # 登录
    # 使用cookie 获取mqtt 配置信息
    get_conf = baseScript.mqtt_conf(cookie)
    # logger.info(f'Cookie={cookie}get_conf ={get_conf} ')
    broker = get_conf['url']
    port = 1883
    appGuestPassword = '123456@appGuest.retone'
    appGuestName = 'appGuest'
    appGuestSendTopic = get_conf['appGuestSendTopic']
    client_id = get_conf['appGuestReceiveClientId']
    appGuestReceiveTopic = get_conf['appGuestReceiveTopic']
    client = connect_mqtt(broker, port, appGuestName, appGuestPassword, appGuestReceiveTopic, client_id, username)
    # 连接订阅消息
    subscribe(client, appGuestReceiveTopic)
    client.loop_forever()



if __name__ == '__main__':
    li = []
    with open('account/protester.txt', mode='r', encoding='utf-8') as f:
        for i in f:
            li.append(i.strip())
    start = time.time()
    tasks = set()
    with ThreadPoolExecutor(2000) as t:
    # # with ThreadPoolExecutor(500) as t:
        for username in li[1000:2000]:
            # if li.index(username) % 4 == 0:
                # logger.info(li.index(username))
                # future = t.submit(run_publish, username.strip())
                # future = t.submit(run_publish, 'username.strip()')
                # tasks.add(future)
            # else:
                future = t.submit(run, username.strip())
                tasks.add(future)
            # if li.index(username) % 50 == 0 and li.index(username) > 0:
            #     time.sleep(2)
    # try:
    #     for future in futures.as_completed(tasks):
    #         err = future.exception()
    #         if err is not None:
    #             raise err
    # except KeyboardInterrupt:
    #     logger.info('stopped by hand')
    #     groups = 250
    #     for i in range(30000, 50000):
    #         future = t.submit(run, f'tester{i}')
    #         tasks.add(future)
    #         if i % groups == 0 and i > 0:
    #             if i > 315000:
    #                 groups = 150
    #             time.sleep(2)
    # try:
    #     for future in futures.as_completed(tasks):
    #         err = future.exception()
    #         if err is not None:
    #             raise err
    # except KeyboardInterrupt:
    #     logger.info('stopped by hand')
    # end = time.time()
    # logger.info(end - start)

    # 使用cookie登录MQTT
    # l = []
    # with open("../locustfiles/cookies.txt") as f:
    #     for account in f:
    #         l.append(account.strip())
    # with ThreadPoolExecutor(15000) as t:
    #     # l 列表控制登录用户数量
    #     for username in l[:15000]:
    #         future = t.submit(__run, username.strip())
